/* ========================================================================== */
/*   IRSensor.cpp    		                                                  */
/*   (c) 2012 Team 7 Hogeschool Utrecht ICT TI                                */
/*		Lars Stolwijk, Gerben Boot, Guido van Hienen, Marcel Boelen			  */
/*                                                                            */
/*   Listens to the IR signal. When a usefull command is received the 		  */
/*		IRSensor looks what he can do with it and subsequently activates 	  */
/*		the next task.														  */
/* ========================================================================== */
#include "IRSensor.h"
armboard::input_pin & irReceiver = armboard::chip::pin_1_24;

IRSensor::IRSensor(int prio, 
		ReadLogHandler * readLogHandler, 
		ProcessHitController * processHitController, 
		OperationController * operationController)
	: RTOS::task(prio, "IRSensorTask"),
	IRSTTimer(RTOS::timer( this,"IRSTTimer" )),
	IRSTClock(this, 800 US, "IRSTClock" ),
	theReadLogHandler(readLogHandler),
	theProcessHitController(processHitController),
	theOperationController(operationController)
{
	irBits = signalBits = receivedSignalBitsCount = pauseCount = 0;
	signal = false;
	irReceiver.direction_set_input();
}

void IRSensor::main()
{
	CurrentState = RUNNING;
	for(;;){
		RTOS::event e = wait( );
		if(CurrentState == RUNNING){
			if(e == IRSTClock){
				ReadIRValue();
			}
		}else if(CurrentState == WAITING){
			if(e == IRSTTimer){
				CurrentState = RUNNING;
			}
		}
	}
}

void IRSensor::ReadIRValue(void){
	char irBit = (irReceiver.get() -1) * -1;	//High Voltage = low bit (invert)
	if(signal){
		if(irBits > 0 || irBit > 0){
			irBits = (irBits << 1) + irBit;
			if(irBits >= 0x4 ){
				receivedSignalBitsCount++;
				if(irBits == 6){ //0b110
					signalBits = (signalBits << 1) + 1;
				}else if(irBits == 4){ //0b100
					signalBits <<= 1;
				}else{//error bits
					SetIRPause();
				}
				irBits = 0;

				if(receivedSignalBitsCount == signalLength){
					CheckIRValue();
					SetIRPause();
				}
			}
		}else{
			SetIRPause();
		}
	}else if(pauseCount > 0){
		pauseCount = irBit == 1 ?  pauseCount = pauseBits : pauseCount-1;
	}else if(irBit)	{
		signal = 1;
		irBits = 1;
	}
}

void IRSensor::SetIRPause(){
	receivedSignalBitsCount = 0;
	signalBits = 0;
	signal = 0;
	irBits= 0;
	pauseCount = pauseBits;
}

bool IRSensor::CheckIRValue(void){
	short xorSignalValue = signalBits;
	for(int i = 0; i < 5; i++){		
		if(((((xorSignalValue & 0x400) >> 5) ^ (xorSignalValue & 0x20)) >> 5) != (xorSignalValue & 0x1)){
			return false;
		}
		xorSignalValue >>= 1;
	}
	char player = (signalBits & 0x7c00) >> 10;
	char weapon = (signalBits & 0x3e0) >> 5;
	if(player == 0){
		if(weapon == 0){
			IRSTTimer.set(2 S);
			theOperationController->PlayEndGame();
		}else if(weapon == 1){
			IRSTTimer.set(2 S);
			theReadLogHandler->ReadLog();
		}
		CurrentState = WAITING;
	}else{
		if(player != _OWN_PLAYER_NUMBER){
			IRSTTimer.set(2 S);
			theProcessHitController->WriteIRResult(IRHitEvent(player,weapon));
			theProcessHitController->Hit();
			CurrentState = WAITING;
		}
	}
	return true;
}
